#pragma once 

/* 实现网关子服务部分的封装 */

#include <functional>
#include <brpc/server.h>
#include <butil/logging.h>
#include <brpc/channel.h>

#include "brpc.hpp"     //Rpc调用模块的封装
#include "etcd.hpp"     //服务注册模块封装
#include "logger.hpp"   //日志模块封装
#include "data_redis.hpp"   //Redis数据管理客户端封装

#include "connection.hpp" //长连接管理的封装

#include "base.pb.h"        //protobuf框架代码
#include "file.pb.h"        //protobuf框架代码
#include "friend.pb.h"      //protobuf框架代码
#include "gateway.pb.h"     //protobuf框架代码
#include "message.pb.h"     //protobuf框架代码
#include "notify.pb.h"     //protobuf框架代码
#include "speech.pb.h"     //protobuf框架代码
#include "transmite.pb.h"     //protobuf框架代码
#include "user.pb.h"        //protobuf框架代码

#include "httplib.h"    //搭建http服务器


namespace ChatSystem
{

    #define GET_PHONE_VERIFY_CODE       "/service/user/get_phone_verify_code"
    #define USERNAME_REGISTER           "/service/user/username_register"
    #define USERNAME_LOGIN              "/service/user/username_login"
    #define PHONE_REGISTER              "/service/user/phone_register"
    #define PHONE_LOGIN                 "/service/user/phone_login"
    #define GET_USERINFO                "/service/user/get_user_info"
    #define SET_USER_AVATAR             "/service/user/set_avatar"
    #define SET_USER_NICKNAME           "/service/user/set_nickname"
    #define SET_USER_DESCRIPTION        "/service/user/set_description"
    #define SET_USER_PHONE              "/service/user/set_phone"
    #define FRIENDGET_LIST             "/service/friend/get_friend_list"
    #define FRIEND_APPLY                "/service/friend/add_friend_apply"
    #define FRIEND_APPLY_PROCESS        "/service/friend/add_friend_process"
    #define FRIEND_REMOVE               "/service/friend/remove_friend"
    #define FRIEND_SEARCH               "/service/friend/search_friend"
    #define FRIEND_GET_PENDING_EVENT    "/service/friend/get_pending_friend_events"
    #define CHAT_SESSION_GET_LIST       "/service/friend/get_chat_session_list"
    #define CHAT_SESSION_CREATE         "/service/friend/create_chat_session"
    #define CHAT_SESSION_GET_MEMBER     "/service/friend/get_chat_session_member"
    #define MESSAGE_GET_RANGE           "/service/message_storage/get_history"
    #define MESSAGE_GET_RECENT          "/service/message_storage/get_recent"
    #define MESSAGE_KEY_SEARCH          "/service/message_storage/search_history"
    #define NEW_MESSAGE                 "/service/message_transmit/new_message"
    #define FILE_GET_SINGLE             "/service/file/get_single_file"
    #define FILE_GET_MULT               "/service/file/get_multi_file"
    #define FILE_PUT_SINGLE             "/service/file/put_single_file"
    #define FILE_PUT_MULT               "/service/file/put_multi_file"
    #define SPEECH_RECOGNITION          "/service/speech/recognition"

    //网关子服务器搭建的流程类
    class GatewayServer
    {
    public:
        using ptr = std::shared_ptr<GatewayServer>;

        GatewayServer(int websocket_port,
            int http_port, 
            const Discovery::ptr& discovery_client, 
            const std::shared_ptr<redis_t>& redis_client,
            const ServiceManager::ptr& channel_manager,
            const std::string& file_service_name,     
            const std::string& friend_service_name,  
            const std::string& message_service_name,  
            const std::string& speech_service_name,  
            const std::string& transmite_service_name,
            const std::string& user_service_name)
        :_discovery_client(discovery_client)
        ,_redis_session(std::make_shared<Session>(redis_client))
        ,_redis_status(std::make_shared<Status>(redis_client))
        ,_channel_manager(channel_manager)
        ,_file_service_name(file_service_name)     
        ,_friend_service_name(friend_service_name)   
        ,_message_service_name(message_service_name) 
        ,_speech_service_name(speech_service_name)  
        ,_transmite_service_name(transmite_service_name)
        ,_user_service_name(user_service_name)     
        {
            //1. 搭建WebSocket服务器
            // 1.1 初始化日志输出---关闭日志输出
            _websocket_server.set_access_channels(websocketpp::log::alevel::none);
            // 1.2 初始化asio框架
            _websocket_server.init_asio();
            // 1.3 设置消息处理、连接握手成功、连接关闭回调函数
            _websocket_server.set_open_handler(std::bind(&GatewayServer::onOpen, this, std::placeholders::_1));
            _websocket_server.set_close_handler(std::bind(&GatewayServer::onClose, this, std::placeholders::_1));
            auto msg_handler = std::bind(&GatewayServer::onMessage, this, std::placeholders::_1, std::placeholders::_2);
            _websocket_server.set_message_handler(msg_handler);
            // 1.4 启用地址重用
            _websocket_server.set_reuse_addr(true);
            // 1.5. 设置监听端口
            _websocket_server.listen(9090);
            // 1.6. 开始监听
            _websocket_server.start_accept();


            //2. 搭建HTTP服务器
            //2.1 注册回调函数 void (const httplib::Request& request, httplib::Response& response)
            _http_server.Post(GET_PHONE_VERIFY_CODE   , (httplib::Server::Handler)std::bind(&GatewayServer::GetPhoneVerifyCode       , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(USERNAME_REGISTER       , (httplib::Server::Handler)std::bind(&GatewayServer::UserRegister             , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(USERNAME_LOGIN          , (httplib::Server::Handler)std::bind(&GatewayServer::UserLogin                , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(PHONE_REGISTER          , (httplib::Server::Handler)std::bind(&GatewayServer::PhoneRegister            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(PHONE_LOGIN             , (httplib::Server::Handler)std::bind(&GatewayServer::PhoneLogin               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(GET_USERINFO            , (httplib::Server::Handler)std::bind(&GatewayServer::GetUserInfo              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_AVATAR         , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserAvatar            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_NICKNAME       , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserNickname          , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_DESCRIPTION    , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserDescription       , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_PHONE          , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserPhoneNumber       , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIENDGET_LIST          , (httplib::Server::Handler)std::bind(&GatewayServer::GetFriendList            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_APPLY            , (httplib::Server::Handler)std::bind(&GatewayServer::FriendAdd                , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_APPLY_PROCESS    , (httplib::Server::Handler)std::bind(&GatewayServer::FriendAddProcess         , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_REMOVE           , (httplib::Server::Handler)std::bind(&GatewayServer::FriendRemove             , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_SEARCH           , (httplib::Server::Handler)std::bind(&GatewayServer::FriendSearch             , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_GET_PENDING_EVENT, (httplib::Server::Handler)std::bind(&GatewayServer::GetPendingFriendEventList, this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(CHAT_SESSION_GET_LIST   , (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionList       , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(CHAT_SESSION_CREATE     , (httplib::Server::Handler)std::bind(&GatewayServer::ChatSessionCreate        , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(CHAT_SESSION_GET_MEMBER , (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionMember     , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(MESSAGE_GET_RANGE       , (httplib::Server::Handler)std::bind(&GatewayServer::GetHistoryMsg            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(MESSAGE_GET_RECENT      , (httplib::Server::Handler)std::bind(&GatewayServer::GetRecentMsg             , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(MESSAGE_KEY_SEARCH      , (httplib::Server::Handler)std::bind(&GatewayServer::MsgSearch                , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(NEW_MESSAGE             , (httplib::Server::Handler)std::bind(&GatewayServer::NewMessage               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_GET_SINGLE         , (httplib::Server::Handler)std::bind(&GatewayServer::GetSingleFile            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_GET_MULT           , (httplib::Server::Handler)std::bind(&GatewayServer::GetMultiFile             , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_PUT_SINGLE         , (httplib::Server::Handler)std::bind(&GatewayServer::PutSingleFile            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_PUT_MULT           , (httplib::Server::Handler)std::bind(&GatewayServer::PutMultiFile             , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SPEECH_RECOGNITION      , (httplib::Server::Handler)std::bind(&GatewayServer::SpeechRecognition        , this, std::placeholders::_1, std::placeholders::_2));

            _http_thread = std::thread([this, http_port]()
            {
                //2.2 启动服务器
                _http_server.listen("0.0.0.0", http_port);  //这个是阻塞接口
            });
            _http_thread.detach();
        }
        ~GatewayServer(){}

        //搭建RPC服务器，并启动服务器
        /* make相关接口的调用必须在start接口调用之前，
        因为start涉及到了启动服务器，而启动服务器的前提是客户端对象和服务注册客户端对象已经实例化好了; 
        为了防止使用者在start接口调用之前未调用 make相关接口而导致
        服务器无法启动的问题，我们可以用建造者模式，将构造过程进行控制，在代码中规定调用顺序，去倒逼使用者;
        使用建造者模式的原因还是由于构造gatewayServer对象时参数太多，为了简化gatewayServer对象的构造 */
        void start()
        {
            //启动服务器
            _websocket_server.run();    //--- 这个也是阻塞接口，所以将http服务器的运行放在了 _http_thread接口中
        }

    private:
        //HTTP对应的回调函数
        //获取短信验证码的接口
        void GetPhoneVerifyCode(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            PhoneVerifyCodeReq req;
            PhoneVerifyCodeRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取短信验证码请求正文反序列化失败！");
                return err_response("获取短信验证码请求正文反序列化失败！");
            }

            //2. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetPhoneVerifyCode(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //3. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //用户名注册的接口
        void UserRegister(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            UserRegisterReq req;
            UserRegisterRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("用户名注册请求正文反序列化失败！");
                return err_response("用户名注册请求正文反序列化失败！");
            }

            //2. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.UserRegister(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //3. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //用户登录接口
        void UserLogin(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            UserLoginReq req;
            UserLoginRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("用户名登录请求正文反序列化失败！");
                return err_response("用户名登录请求正文反序列化失败！");
            }

            //2. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.UserLogin(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //3. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //手机号注册接口
        void PhoneRegister(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            PhoneRegisterReq req;
            PhoneRegisterRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("手机号注册请求正文反序列化失败！");
                return err_response("手机号注册请求正文反序列化失败！");
            }

            //2. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PhoneRegister(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //3. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //手机号登录接口
        void PhoneLogin(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            PhoneLoginReq req;
            PhoneLoginRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("手机号登录请求正文反序列化失败！");
                return err_response("手机号登录请求正文反序列化失败！");
            }

            //2. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PhoneLogin(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //3. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取用户信息接口
        void GetUserInfo(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetUserInfoReq req;
            GetUserInfoRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取用户信息请求正文反序列化失败！");
                return err_response("获取用户信息请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());

            //3. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetUserInfo(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //4. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //设置用户头像接口
        void SetUserAvatar(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            SetUserAvatarReq req;
            SetUserAvatarRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("设置用户头像请求正文反序列化失败！");
                return err_response("设置用户头像请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserAvatar(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //4. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //设置用户昵称接口
        void SetUserNickname(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            SetUserNicknameReq req;
            SetUserNicknameRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("设置用户昵称请求正文反序列化失败！");
                return err_response("设置用户昵称请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserNickname(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //4. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //设置用户签名接口
        void SetUserDescription(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            SetUserDescriptionReq req;
            SetUserDescriptionRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("设置用户签名请求正文反序列化失败！");
                return err_response("设置用户签名请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserDescription(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //4. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //设置用户手机号码接口
        void SetUserPhoneNumber(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            SetUserPhoneNumberReq req;
            SetUserPhoneNumberRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("设置用户手机号码请求正文反序列化失败！");
                return err_response("设置用户手机号码请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给用户子服务进行业务处理
            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", req.request_id(), _user_service_name);
                return err_response("未找到用户管理子服务节点！");
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserPhoneNumber(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", req.request_id(), _user_service_name, cntl.ErrorText());
                return err_response("用户管理子服务Rpc调用失败!");
            }

            //4. 得到用户子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取好友列表接口
        void GetFriendList(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetFriendListReq req;
            GetFriendListRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取好友列请求正文反序列化失败！");
                return err_response("获取好友列请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetFriendList(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //从用户子服务器中获取用户信息
        std::shared_ptr<GetUserInfoRsp> _GetUserInfo(const std::string& request_id, const std::string& user_id)
        {
            GetUserInfoReq req;
            std::shared_ptr<GetUserInfoRsp> rsp = std::make_shared<GetUserInfoRsp>();

            req.set_request_id(request_id);
            req.set_user_id(user_id);

            auto channel = _channel_manager->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到用户管理子服务节点 - {}!", request_id, _user_service_name);
                return std::shared_ptr<GetUserInfoRsp>();
            }
            ChatSystem::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetUserInfo(&cntl, &req, rsp.get(), nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 用户管理子服务 {} Rpc调用失败, {}!", request_id, _user_service_name, cntl.ErrorText());
                return std::shared_ptr<GetUserInfoRsp>();
            }
            return rsp;
        }
        
        //好友申请接口
        void FriendAdd(const httplib::Request& request, httplib::Response& response)
        {
            //好友申请的业务处理中，好友子服务其实只是在数据库中创建了好友申请事件，
            //网关需要做的事情，当好友子服务将业务处理完毕后，如果是处理成功的---需要通知被申请方

            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            FriendAddReq req;
            FriendAddRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("好友申请请求正文反序列化失败！");
                return err_response("好友申请请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendAdd(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())  
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 若业务处理成功且获取被申请方长连接成功，则向被申请方进行好友申请事件通知
            auto conn = _connections->connection(user_id.value());
            if(rsp.success() && conn)
            {
                auto user_rsp = _GetUserInfo(req.request_id(), user_id.value());
                if(!user_rsp)
                {
                    LOG_ERROR("{} - 获取当前客户端 {} 用户信息失败 - {}!", req.request_id(), user_id.value());
                    return err_response("获取当前客户端用户信息失败！");
                }
                NotifyMessage notify;
                notify.set_notify_type(NotifyType::FRIEND_ADD_APPLY_NOTIFY);
                notify.mutable_friend_add_apply()->mutable_user_info()->CopyFrom(user_rsp->user_info());
                conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }

            //5. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //好友申请处理接口
        void FriendAddProcess(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化，提取要素：登录会话ID、处理结果、申请人
            FriendAddProcessReq req;
            FriendAddProcessRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("好友申请处理请求正文反序列化失败！");
                return err_response("好友申请处理请求正文反序列化失败！");
            }
            bool agree = req.agree();
            std::string apply_user_id = req.apply_user_id();

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendAddProcess(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed()) 
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            if(rsp.success())
            {
                //获取申请人和处理人的用户信息
                auto apply_user_rsp = _GetUserInfo(req.request_id(), apply_user_id);
                if(!apply_user_rsp)
                {
                    LOG_ERROR("{} - 获取当前客户端 {} 用户信息失败 - {}!", req.request_id(), apply_user_id);
                    return err_response("获取当前客户端用户信息失败！");
                }
                auto process_user_rsp = _GetUserInfo(req.request_id(), user_id.value());
                if(!process_user_rsp)
                {
                    LOG_ERROR("{} - 获取当前客户端 {} 用户信息失败 - {}!", req.request_id(), user_id.value());
                    return err_response("获取当前客户端用户信息失败！");
                }
                auto process_conn = _connections->connection(user_id.value());
                auto apply_conn = _connections->connection(apply_user_id);
                //4. 将处理结果给申请人进行通知
                if(process_conn)
                {
                    NotifyMessage notify;
                    notify.set_notify_type(NotifyType::FRIEND_ADD_PROCESS_NOTIFY);
                    auto process_result = notify.mutable_friend_process_result();
                    process_result->mutable_user_info()->CopyFrom(process_user_rsp->user_info());
                    process_result->set_agree(agree);
                    apply_conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
                }

                //5. 若处理结果是同意，会伴随着单聊会话的创建，因此需要对双方进行会话创建的通知
                if(agree && apply_conn) //对申请人进行会话创建的通知 --- 会话信息就是处理人的信息
                {
                    NotifyMessage notify;
                    notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                    auto chat_session = notify.mutable_new_chat_session_info();
                    chat_session->mutable_chat_session_info()->set_single_chat_friend_id(user_id.value());
                    chat_session->mutable_chat_session_info()->set_chat_session_id(rsp.new_chat_session_id());
                    chat_session->mutable_chat_session_info()->set_chat_session_name(process_user_rsp->user_info().nickname());
                    chat_session->mutable_chat_session_info()->set_avatar(process_user_rsp->user_info().avatar());
                    apply_conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
                }

                if(agree && process_conn)//对处理人进行会话创建的通知 --- 会话信息就是申请人的信息
                {
                    NotifyMessage notify;
                    notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                    auto chat_session = notify.mutable_new_chat_session_info();
                    chat_session->mutable_chat_session_info()->set_single_chat_friend_id(apply_user_id);
                    chat_session->mutable_chat_session_info()->set_chat_session_id(rsp.new_chat_session_id());
                    chat_session->mutable_chat_session_info()->set_chat_session_name(apply_user_rsp->user_info().nickname());
                    chat_session->mutable_chat_session_info()->set_avatar(apply_user_rsp->user_info().avatar());
                    process_conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
                }
                
            }

            //6. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //删除好友接口
        void FriendRemove(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            FriendRemoveReq req;
            FriendRemoveRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("删除好友请求正文反序列化失败！");
                return err_response("删除好友请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendRemove(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 若业务处理成功且获取被删除方长连接成功，则向被删除方进行好友申请事件通知
            auto conn = _connections->connection(req.peer_id());
            if(rsp.success() && conn)
            {
                NotifyMessage notify;
                notify.set_notify_type(NotifyType::FRIEND_REMOVE_NOTIFY);
                notify.mutable_friend_remove()->set_user_id(user_id.value());
                conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }

            //5. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //用户搜索接口
        void FriendSearch(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            FriendSearchReq req;
            FriendSearchRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("用户搜索请求正文反序列化失败！");
                return err_response("用户搜索请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendSearch(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取待处理的好友申请事件接口
        void GetPendingFriendEventList(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetPendingFriendEventListReq req;
            GetPendingFriendEventListRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取待处理的好友申请事件请求正文反序列化失败！");
                return err_response("获取待处理的好友申请事件请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetPendingFriendEventList(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取聊天会话列表
        void GetChatSessionList(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetChatSessionListReq req;
            GetChatSessionListRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取聊天会话列表请求正文反序列化失败！");
                return err_response("获取聊天会话列表请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetChatSessionList(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取聊天会话成员接口
        void GetChatSessionMember(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetChatSessionMemberReq req;
            GetChatSessionMemberRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取聊天会话成员请求正文反序列化失败！");
                return err_response("获取聊天会话成员请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetChatSessionMember(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 得到好友管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //创建聊天会话接口
        void ChatSessionCreate(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            ChatSessionCreateReq req;
            ChatSessionCreateRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("创建聊天会话请求正文反序列化失败！");
                return err_response("创建聊天会话请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给好友管理子服务进行业务处理
            auto channel = _channel_manager->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到好友管理子服务节点 - {}!", req.request_id(), _friend_service_name);
                return err_response("未找到好友管理子服务节点！");
            }
            ChatSystem::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.ChatSessionCreate(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 好友管理子服务 {} Rpc调用失败, {}!", req.request_id(), _friend_service_name, cntl.ErrorText());
                return err_response("好友管理子服务Rpc调用失败!");
            }

            //4. 若业务处理成功且群聊会话成员的长连接获取成功，则向每个群聊成员进行群聊会话创建的通知
            if(rsp.success())
            {
                for(int i = 0; i < req.member_id_list_size(); ++i)
                {
                    auto conn = _connections->connection(req.member_id_list(i));
                    if(!conn)
                    {
                        continue;
                    }
                    NotifyMessage notify;
                    notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                    auto chat_session = notify.mutable_new_chat_session_info();
                    chat_session->mutable_chat_session_info()->CopyFrom(rsp.chat_session_info());
                    conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
                }
            }     

            //5. 向客户端进行响应 
            rsp.clear_chat_session_info();  //由于有专门的会话创建成功后的事件通知，所以不需要将chat_session_info中的信息响应给客户端
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取指定时间段的消息接口
        void GetHistoryMsg(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetHistoryMsgReq req;
            GetHistoryMsgRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取指定时间段的消息请求正文反序列化失败！");
                return err_response("获取指定时间段的消息请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给消息存储子服务进行业务处理
            auto channel = _channel_manager->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到消息存储子服务节点 - {}!", req.request_id(), _message_service_name);
                return err_response("未找到消息存储子服务节点！");
            }
            ChatSystem::MsgStorageService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetHistoryMsg(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 消息存储子服务 {} Rpc调用失败, {}!", req.request_id(), _message_service_name, cntl.ErrorText());
                return err_response("消息存储子服务Rpc调用失败!");
            }

            //4. 得到消息存储子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //获取最近的N条消息接口
        void GetRecentMsg(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetRecentMsgReq req;
            GetRecentMsgRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("获取最近的N条消息请求正文反序列化失败！");
                return err_response("获取最近的N条消息请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给消息存储子服务进行业务处理
            auto channel = _channel_manager->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到消息存储子服务节点 - {}!", req.request_id(), _message_service_name);
                return err_response("未找到消息存储子服务节点！");
            }
            ChatSystem::MsgStorageService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetRecentMsg(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 消息存储子服务 {} Rpc调用失败, {}!", req.request_id(), _message_service_name, cntl.ErrorText());
                return err_response("消息存储子服务Rpc调用失败!");
            }

            //4. 得到消息存储子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //关键字搜索消息的接口
        void MsgSearch(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            MsgSearchReq req;
            MsgSearchRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("关键字搜索消息请求正文反序列化失败！");
                return err_response("关键字搜索消息请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给消息存储子服务进行业务处理
            auto channel = _channel_manager->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到消息存储子服务节点 - {}!", req.request_id(), _message_service_name);
                return err_response("未找到消息存储子服务节点！");
            }
            ChatSystem::MsgStorageService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.MsgSearch(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 消息存储子服务 {} Rpc调用失败, {}!", req.request_id(), _message_service_name, cntl.ErrorText());
                return err_response("消息存储子服务Rpc调用失败!");
            }

            //4. 得到消息存储子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //单个文件下载接口
        void GetSingleFile(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetSingleFileReq req;
            GetSingleFileRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("单个文件下载请求正文反序列化失败！");
                return err_response("单个文件下载请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给文件管理子服务进行业务处理
            auto channel = _channel_manager->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到文件管理子服务节点 - {}!", req.request_id(), _file_service_name);
                return err_response("未找到文件管理子服务节点！");
            }
            ChatSystem::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetSingleFile(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 文件管理子服务 {} Rpc调用失败, {}!", req.request_id(), _file_service_name, cntl.ErrorText());
                return err_response("文件管理子服务Rpc调用失败!");
            }

            //4. 得到文件管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //多文件下载接口
        void GetMultiFile(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            GetMultiFileReq req;
            GetMultiFileRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("多文件下载请求正文反序列化失败！");
                return err_response("多文件下载请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给文件管理子服务进行业务处理
            auto channel = _channel_manager->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到文件管理子服务节点 - {}!", req.request_id(), _file_service_name);
                return err_response("未找到文件管理子服务节点！");
            }
            ChatSystem::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetMultiFile(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 文件管理子服务 {} Rpc调用失败, {}!", req.request_id(), _file_service_name, cntl.ErrorText());
                return err_response("文件管理子服务Rpc调用失败!");
            }

            //4. 得到文件管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //单文件上传接口
        void PutSingleFile(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            PutSingleFileReq req;
            PutSingleFileRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("单文件上传请求正文反序列化失败！");
                return err_response("单文件上传请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给文件管理子服务进行业务处理
            auto channel = _channel_manager->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到文件管理子服务节点 - {}!", req.request_id(), _file_service_name);
                return err_response("未找到文件管理子服务节点！");
            }
            ChatSystem::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PutSingleFile(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 文件管理子服务 {} Rpc调用失败, {}!", req.request_id(), _file_service_name, cntl.ErrorText());
                return err_response("文件管理子服务Rpc调用失败!");
            }

            //4. 得到文件管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //多文件上传接口
        void PutMultiFile(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            PutMultiFileReq req;
            PutMultiFileRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("多文件上传请求正文反序列化失败！");
                return err_response("多文件上传请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给文件管理子服务进行业务处理
            auto channel = _channel_manager->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到文件管理子服务节点 - {}!", req.request_id(), _file_service_name);
                return err_response("未找到文件管理子服务节点！");
            }
            ChatSystem::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PutMultiFile(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 文件管理子服务 {} Rpc调用失败, {}!", req.request_id(), _file_service_name, cntl.ErrorText());
                return err_response("文件管理子服务Rpc调用失败!");
            }

            //4. 得到文件管理子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //语音识别接口
        void SpeechRecognition(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            SpeechRecognitionReq req;
            SpeechRecognitionRsp rsp;

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("语音识别请求正文反序列化失败！");
                return err_response("语音识别请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给语音识别子服务进行业务处理
            auto channel = _channel_manager->choose(_speech_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到语音识别子服务节点 - {}!", req.request_id(), _speech_service_name);
                return err_response("未找到语音识别子服务节点！");
            }
            ChatSystem::SpeechService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SpeechRecognition(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 语音识别子服务 {} Rpc调用失败, {}!", req.request_id(), _speech_service_name, cntl.ErrorText());
                return err_response("语音识别子服务Rpc调用失败!");
            }

            //4. 得到语音识别子服务器的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

        //新消息的产生接口 --- 对客户端来说是产生了新消息，而对子服务之间来说是获取消息转发目标
        void NewMessage(const httplib::Request& request, httplib::Response& response)
        {
            //1. 从HTTP请求中取出正文信息，将正文进行反序列化
            NewMessageReq req;
            NewMessageRsp rsp;  //这是给客户端的响应
            GetTransmiteTargetRsp target_rsp;   //这是给请求服务器的响应

            //定义一个错误处理函数，当出错的时候被调用
            auto err_response = [&req, &rsp, &response](const std::string& errmsg)->void
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);

                response.set_content(rsp.SerializeAsString(), "application/x-protobuf");
                return;
            };

            bool ret = req.ParseFromString(request.body);
            if(ret == false)
            {
                LOG_ERROR("新消息的产生请求正文反序列化失败！");
                return err_response("新消息的产生请求正文反序列化失败！");
            }

            //2. 客户端身份识别与鉴权
            std::string login_session_id = req.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            if(!user_id)
            {
                LOG_ERROR("{} - 获取登录会话 {} 关联用户信息失败！", req.request_id(), login_session_id);
                return err_response("获取登录会话关联用户信息失败！");
            }
            //由网关子服务设置请求的用户ID
            req.set_user_id(user_id.value());
            
            //3. 将请求转发给消息转发子服务进行业务处理 --- 获取消息转发目标
            auto channel = _channel_manager->choose(_transmite_service_name);
            if(!channel)
            {
                LOG_ERROR("{} - 未找到消息转发子服务节点 - {}!", req.request_id(), _transmite_service_name);
                return err_response("未找到消息转发子服务节点！");
            }
            ChatSystem::MsgTransmiteService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetTransmiteTarget(&cntl, &req, &target_rsp, nullptr);
            if(cntl.Failed())   //网关服务器只关心RPC调用是否成功，不关心对应的操作是否成功；客户端才关心对应的操作是否成功；
            {
                LOG_ERROR("{} - 消息转发子服务 {} Rpc调用失败, {}!", req.request_id(), _transmite_service_name, cntl.ErrorText());
                return err_response("消息转发子服务Rpc调用失败!");
            }

            //4. 若业务处理成功---网关子服务将消息转发给每个转发目标用户
            if(target_rsp.success())
            {
                for(int i = 0; i < target_rsp.target_id_list_size(); ++i)
                {
                    auto conn = _connections->connection(target_rsp.target_id_list(i));
                    if(!conn)
                    {
                        continue;
                    }
                    NotifyMessage notify;
                    notify.set_notify_type(NotifyType::CHAT_MESSAGE_NOTIFY);
                    auto message_info = notify.mutable_new_message_info();
                    message_info->mutable_message_info()->CopyFrom(target_rsp.message());
                    conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary);
                }
            }

            //5. 向客户端进行响应 --- 使用rsp进行响应
            rsp.set_request_id(req.request_id());
            rsp.set_success(target_rsp.success());
            rsp.set_errmsg(target_rsp.errmsg());
            response.set_content(rsp.SerializeAsString(), "application/x-protobuf"); //application/x-protobuf表示protobuf类型的正文
        }

    private:
        //WebSocket对应的回调函数 --- 长连接主要用户服务器向客户端推送消息
        void onOpen(websocketpp::connection_hdl hdl)
        {
            //这里不需要进行处理，因为长连接刚建立成功的时候不知道这个长连接是属于哪个客户端的；
            //在客户端发送第一条消息之后就知道了这个长连接是属于哪个客户端的，所以对长连接的处理应该是在收到第一条消息中，也就是onMessage中处理
            LOG_INFO("websocket 长连接建立成功！");
        }
        void onClose(websocketpp::connection_hdl hdl)
        {
            //长连接断开时做的清理工作
            //1.通过连接对象，获取对应的用户ID与登录会话ID
            auto conn = _websocket_server.get_con_from_hdl(hdl);
            std::string user_id, login_session_id;
            bool ret = _connections->client(conn, user_id, login_session_id);
            if(ret == false)
            {
                LOG_WARN("长连接断开，未找到长连接对应的客户端信息！");
                return;
            }
            //2.移除登录会话信息 
            _redis_session->remove(login_session_id);

            //3.移除登录状态信息
            _redis_status->remove(user_id);

            //4.移除长连接管理数据 
            _connections->remove(conn);

            LOG_INFO("{} - {} - {}长连接断开, 清理缓存数据！", login_session_id, user_id, (size_t)conn.get());
        }
        void onMessage(websocketpp::connection_hdl hdl, server_t::message_ptr msg)
        {
            //从头到尾客户端给WebSocket服务器只会发送一条消息，这条消息就是用于身份识别，知道长连接是属于哪个客户端的；
            //当客户端和网关服务器建立长连接之后要发送一条请求里面带有请求ID和登录会话ID，其中的登录会话ID是用于表明当前长连接客户端的身份
            //收到第一条消息后，根据消息中的会话ID进行身份识别，将客户端长连接添加管理
            //1. 取出长连接对应的连接对象
            auto conn = _websocket_server.get_con_from_hdl(hdl);

            //2. 针对消息内容进行反序列化 --- ClientAuthenticationReq 这种结构，提取登录会话ID
            ClientAuthenticationReq request;
            bool ret = request.ParseFromString(msg->get_payload());
            if(ret == false)
            {
                LOG_ERROR("长连接身份识别失败：正文反序列化失败！");
                _websocket_server.close(hdl, websocketpp::close::status::unsupported_data, "正文反序列化失败!");
            }
            
            //3. 在登录会话信息缓存中，查找会话信息
            std::string login_session_id = request.login_session_id();
            auto user_id = _redis_session->uid(login_session_id);
            
            //4. 会话信息不存在则关闭连接
            if(!user_id)
            {
                LOG_ERROR("长连接身份识别失败：未找到会话信息 {} ！", login_session_id);
                _websocket_server.close(hdl, websocketpp::close::status::unsupported_data, "未找到会话信息!");
            }
            //5. 会话信息存在，则添加长连接
            _connections->insert(conn, user_id.value(), login_session_id);
            LOG_DEBUG("新增长连接管理：{} - {} - {}", login_session_id, user_id.value(), (size_t)conn.get());
        }

    private:
        Discovery::ptr _discovery_client;    //服务发现客户端

        Session::ptr _redis_session;
        Status::ptr _redis_status;

        std::string _file_service_name;     //文件管理子服务名称
        std::string _friend_service_name;   //好友管理子服务名称
        std::string _message_service_name;  //消息存储子服务名称
        std::string _speech_service_name;   //语音识别子服务名称
        std::string _transmite_service_name;//消息转发子服务名称
        std::string _user_service_name;     //用户管理子服务名称
        ServiceManager::ptr _channel_manager;    //Rpc调用中信道管理对象

        Connection::ptr _connections;   //长连接管理对象
        server_t _websocket_server;     //WebSocket 服务器
        httplib::Server _http_server;   //http服务器
        std::thread _http_thread;   //http的运行线程

    };

    //建造者模式---用来构造GatewayServer对象，将GatewayServer对象的真正构造过程给封装起来，通过封装的类去构造 GatewayServer 对象
    class GatewayServerBuilder
    {
    public:

        //构造redis客户端对象
        void make_redis_object(const std::string& host,
            int port,
            int db,
            bool keep_alive)
        {
            _redis_client = RedisClientFactory::creat(host, port, db, keep_alive);
        }

        //设置端口信息
        void make_server_object(int websocket_port, int http_port)
        {
            _websocket_port = websocket_port;
            _http_port = http_port;
        }

        //构造服务发现客户端对象和信道管理对象
        void make_discovery_object(const std::string& reg_host,
            const std::string& base_service_name,
            const std::string& file_service_name,     
            const std::string& friend_service_name,  
            const std::string& message_service_name,  
            const std::string& speech_service_name,  
            const std::string& transmite_service_name,
            const std::string& user_service_name)
        {
            _file_service_name = file_service_name;         
            _friend_service_name = friend_service_name;    
            _message_service_name = message_service_name;    
            _speech_service_name = speech_service_name;       
            _transmite_service_name = transmite_service_name;
            _user_service_name = user_service_name;

            _channel_manager = std::make_shared<ServiceManager>();
            _channel_manager->declared(_file_service_name);
            _channel_manager->declared(_friend_service_name);
            _channel_manager->declared(_message_service_name);
            _channel_manager->declared(_speech_service_name);
            _channel_manager->declared(_transmite_service_name);
            _channel_manager->declared(_user_service_name);
            LOG_DEBUG("设置文件管理子服务为需要添加管理的子服务：{}", _file_service_name);
            LOG_DEBUG("设置好友管理子服务为需要添加管理的子服务：{}", _friend_service_name);
            LOG_DEBUG("设置消息存储子服务为需要添加管理的子服务：{}", _message_service_name);
            LOG_DEBUG("设置语音识别子服务为需要添加管理的子服务：{}", _speech_service_name);
            LOG_DEBUG("设置消息转发子服务为需要添加管理的子服务：{}", _transmite_service_name);
            LOG_DEBUG("设置用户管理子服务为需要添加管理的子服务：{}", _user_service_name);
            auto put_cb = std::bind(&ChatSystem::ServiceManager::onServiceOnline, 
                _channel_manager.get(), 
                std::placeholders::_1, 
                std::placeholders::_2);
            auto del_cb = std::bind(&ChatSystem::ServiceManager::onServiceOffline, 
                _channel_manager.get(), 
                std::placeholders::_1,
                std::placeholders::_2);
            //2. 构造服务发现对象 
            _discovery_client = std::make_shared<ChatSystem::Discovery>(reg_host, base_service_name, put_cb, del_cb);
        }

        //构造一个 GatewayServer 对象
        GatewayServer::ptr build()
        {
            if(!_redis_client)
            {
                LOG_ERROR("还未初始化Redis数据库模块！");
                abort();
            }
            if(!_channel_manager)
            {
                LOG_ERROR("还未初始化信道管理模块！");
                abort();
            }
            if(!_discovery_client)
            {
                LOG_ERROR("还未初始化服务发现模块！");
                abort();
            }

            GatewayServer::ptr server = std::make_shared<GatewayServer>(_websocket_port,
                _http_port,
                _discovery_client, 
                _redis_client,
                _channel_manager,
                _file_service_name,     
                _friend_service_name,   
                _message_service_name,  
                _speech_service_name,   
                _transmite_service_name,
                _user_service_name);

            return server;
        }
    private:
        int _websocket_port;    //websocket服务器的端口号
        int _http_port;         //http服务器的端口号
        std::string _file_service_name;     //文件管理子服务名称
        std::string _friend_service_name;   //好友管理子服务名称
        std::string _message_service_name;  //消息存储子服务名称
        std::string _speech_service_name;   //语音识别子服务名称
        std::string _transmite_service_name;//消息转发子服务名称
        std::string _user_service_name;     //用户管理子服务名称
        ServiceManager::ptr _channel_manager;   //信道管理对象

        std::shared_ptr<redis_t> _redis_client; //Redis客户端
        Discovery::ptr _discovery_client;    //服务发现客户端对象

    };

}